package com.apestech.formwork.stream;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

import com.apestech.framework.db.SqlResultSet;
import com.apestech.framework.db.callback.QueryCallBackHandler;
import com.apestech.framework.dictionary.lib.TableRowHander;
import com.apestech.framework.file.BufferFile;
import com.apestech.framework.file.FileDictionary.LogSaveType;
import com.apestech.framework.file.callback.BufferFileInter;
import com.apestech.framework.file.callback.ReadBufferFileCallBackHandler;
import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.metadata.MetaData;
import com.apestech.framework.stream.ArrayObject;
import com.apestech.framework.stream.callback.ReadRowHander;
import com.apestech.framework.util.DBUtil;
import com.apestech.framework.util.FileUtil;
import com.apestech.framework.util.LocalVariable;
import com.apestech.framework.util.StringUtil;

/**
 * 将指定类型变量数据转成流文件模式入口调用函数，获取数据为文本
 * @author hupo
 *
 */
public class ListStream extends StringUtil implements  BufferFileInter {
	
	private String filename=null;
	private final BufferFile file;
	private ArrayObject list;
	private LogSaveType saveType=LogSaveType.COUNT;
	private String keyField=null;
	private String pinyinField=null;
	private int keyLength=1;
	
	public ListStream() throws Exception {
		getNFileName();
		this.file=new BufferFile(this.filename);
	}
	
	public ListStream(String filename) throws Exception{
		this.filename=filename;
		this.file=new BufferFile(this.filename);
		this.file.initIndex();
	}
	
	public ListStream(int fetchSize) throws Exception {
		getNFileName();
		this.file=new BufferFile(this.filename, fetchSize);
	}
	
	public ListStream(String filename, int fetchSize, LogSaveType saveType) throws Exception {
		this.filename=filename;
		this.file=new BufferFile(this.filename, fetchSize, saveType);
	}
	
	public ListStream(int fetchSize, LogSaveType saveType) throws Exception {
		getNFileName();
		this.file=new BufferFile(this.filename, fetchSize, saveType);
	}
	
	public ListStream(ArrayObject obj) throws Exception{
		getNFileName();
		this.file=new BufferFile(this.filename);
		iniObjData(obj);
	}
	
	public ListStream(int fetchSize, ArrayObject obj) throws Exception{
		getNFileName();
		this.file=new BufferFile(this.filename, fetchSize);
		iniObjData(obj);
	}
	
	public void setSaveType(LogSaveType saveType){
		this.saveType=saveType;
		this.file.setSaveType(saveType);
	}
	
	public void setKeyField(String keyField){
		this.keyField=keyField;
		this.file.setKeyField(keyField);
	}
	
	public void setKeyLength(int keyLength){
		this.keyLength=keyLength;
		this.file.setKeyLength(keyLength);
	}
	
	public void setPinyinField(String pinyinField){
		this.pinyinField=pinyinField;
		this.file.setPinyinField(pinyinField);
	}
	
	public void write(ArrayObject obj) throws Exception{
		iniObjData(obj);
	}
	
	public void write(ArrayObject obj, int pos) throws Exception{
		iniObjData(obj, pos);
	}

	public QueryCallBackHandler write(MetaData md) throws Exception {
		return new QueryCallBackHandler(){
			@Override
			public void getData(SqlResultSet rs, JSONArray rslist) throws Exception {
				write(new ArrayObject(rs), new ArrayObjectStreamHander(rs, new TableRowHander(rs, md)), -1);
			}
		};
	}

	public void write(ArrayObject obj, ReadRowHander readRowHander) throws Exception{
		write(obj, readRowHander, -1);
	}
	
	public void write(ArrayObject obj, ReadRowHander readRowHander, int maxCount) throws Exception{
		iniObjData(obj, readRowHander, maxCount);
		//obj.close();
		//this.file.close();
	}
	
	public void writeIndexFile() throws Exception{
		String sfile=this.filename+ DBUtil.getSysInfo().getFileSeparator()+"index.txt";
		File tfile=FileUtil.newFile(sfile);
		OutputStream out = new FileOutputStream(tfile);
		byte[] b=(JSON.toJSONString(this.file.toJSON())).getBytes();
		out.write(b,0,b.length); 
		out.flush();
		out.close();
	}
	
	private void getNFileName() throws Exception {
		if(this.filename==null){
			this.filename= FileUtil.getFileNameForSys(LocalVariable.getTempDir()+this.getUUID());
		}  
	}
	
	public String getFileName(){
		return this.filename;
	}
	
	
	private void iniObjData(ArrayObject obj) throws Exception{
		this.file.write(new ArrayObjectWriteFile(obj, 0){
			protected String write(ArrayObject obj, int index) throws Exception {
				return obj.getText();
			}
		});
		writeIndexFile();
	}
	
	private void iniObjData(ArrayObject obj, final ReadRowHander readRowHander, final int maxCount) throws Exception{
		this.file.write(new ArrayObjectWriteFile(obj, 0, maxCount){
			protected String write(ArrayObject obj, int index) throws Exception {
				return readRowHander.processRow(index);
			}
		});
		writeIndexFile();
	}
	
	private void iniObjData(ArrayObject obj, int pos) throws Exception{
		this.file.write(new ArrayObjectWriteFile(obj, pos){
			protected String write(ArrayObject obj, int index) throws Exception {
				return obj.getText();
			}
		});
	}

	public void setFetchSize(int fetchSize){
		this.file.setFetchSize(fetchSize);
	}
	
	public int getFetchSize(){
		return this.file.getFetchSize();
	}
	
	public int size() throws Exception {
		return this.file.size();
	}
	
	public int getFileCount(){
		return this.file.fileCount();
	}
	
	public void addPage(int row){
		this.file.addPage(row);
	}
	
	public void addPage(String key, int row){
		this.file.addPage(key, row);
	}
	
	public void add(String text) throws Exception{
		this.file.add(text);
	}
	
	public void setIndex(int index){
		this.file.setIndex(index);
	}

	public int getIndex(){
		return this.file.getIndex();
	}
	
	public int getIndex(String keyValue) throws Exception{
		return this.file.getIndex(keyValue);
	}
	
	public String getText() throws Exception{
		return this.file.getText();
	}
	
	public String getText(int index) throws Exception{
		return this.file.getText(index);
	}
	
	public boolean bof(){
		return this.file.bof();
	}
	
	public boolean first() {
		return this.file.first();
	}

	public boolean previous() {
		return this.file.previous();
	}

	public boolean next() throws Exception {
		return this.file.next();
	}

	public boolean last() throws Exception {
		return this.file.last();
	}

	public void clear() throws Exception {
		this.file.clear();
	}

	public void close() throws IOException {
		this.file.close();
	}
	
	public void readKey(String key, ReadBufferFileCallBackHandler readBufferFileCallBackHandler) throws Exception{
		this.file.readKey(key, readBufferFileCallBackHandler);
	}
	
	public void read(int page, ReadBufferFileCallBackHandler readBufferFileCallBackHandler) throws Exception{
		this.file.read(page, readBufferFileCallBackHandler);
	}
	
	public void read(String key, ReadBufferFileCallBackHandler readBufferFileCallBackHandler) throws Exception{
		this.file.read(key, readBufferFileCallBackHandler);
	}
	
	public ArrayList<String> getKeyList(){
		return this.file.getKeyList();
	}
	
	public String toString(){
		StringBuilder sb=new StringBuilder();
		sb.append("\rdir: "+this.filename);
		sb.append(this.file.toString());
		return sb.toString();
	}
	
	public String getFileIndexString(int index){
		return this.file.getFileIndexString(index);
	}
	
	private void getPageRow(int page, int size, ReadBufferFileCallBackHandler readBufferFileCallBackHandler) throws Exception{
		int start=(page-1)*size+1;
		int end=page*size;
		for(int i=start; i<=end; i++){
			String text=this.getText(i-1);
			if(text==null) break;
			readBufferFileCallBackHandler.read(text, i-1);
		}
	}
	
	private ByteArrayOutputStream getPageRow(int page, int size) throws Exception{
		final ByteArrayOutputStream os=new ByteArrayOutputStream();
		os.write("[".getBytes());
		getPageRow(page, size, new ReadBufferFileCallBackHandler(){
			
			private boolean flag=false;
			
			public boolean read(String text, int index) throws Exception {
				if(flag){
					os.write(",".getBytes());
				}
				os.write(text.getBytes());
				if(!flag){
					flag=true;
				}
				return false;
			}
		});
		
		os.write("]".getBytes());
		return os;
		
	}
	
	public byte[] getPageAsByte(int page, int size) throws Exception{
		return getPageRow(page, size).toByteArray();
	}
	
	public String getPageAsString(int page, int size) throws Exception{
		return getPageRow(page, size).toString();
	}
	
	public void getPageAsOutput(OutputStream os, int page, int size) throws Exception{
		byte[] b=getPageAsByte(page, size);
		os.write(b,0,b.length);
	}
	
	public JSONArray getPageAsJSONArray(int page, int size) throws Exception{
		final JSONArray list=new JSONArray();
		getPageRow(page, size, new ReadBufferFileCallBackHandler(){
			public boolean read(String text, int index) throws Exception {
				list.add(text);
				return false;
			}
		});
		return list;
	}
	
}
